#include <lcthw/linklist.h>
#include <lcthw/dbg.h>
#include <stdlib.h>
#include <stdio.h>

// Initialize an empty linked list
LinkList Init_List()
{
    LinkList L = (LinkList)malloc(sizeof(Node));
    if (L == NULL)
    {
        log_err("Failed to allocate memory for the linked list");
        return NULL;
    }
    L->next = NULL;
    return L;
}

// Destroy a linked list
void Destroy_List(LinkList L)
{
    Clear_List(L);           // All nodes are freed
    free(L);                // Free the head node
    L = NULL;               // Set the head node to NULL, to avoid wild pointers
}

// Clear a linked list
void Clear_List(LinkList L)
{
    LinkList p = L->next;
    while (p != NULL)
    {
        LinkList q = p->next;
        free(p);
        p = q;
    }
    L->next = NULL;
}

// Check if a linked list is empty
int List_Empty(LinkList L)                   // If list is empty, return 1; otherwise, return 0
{
    return L->next == NULL;                 // If the head node points to NULL, the list is empty
}

// Get the length of a linked list
int List_Length(LinkList L)
{
    int length = 0;
    LinkList p = L->next;                   // p points to the first node
    while (p != NULL)
    {
        length++;
        p = p->next;
    }
    return length;
}

// Get the element at position i, 1 <= i <= ListLength(L)
int Get_Elem(LinkList L, int i, ElemType *e)
{
    int j = 1;                                  // j is the counter
    LinkList p = L->next;                        // p points to the first node
    while (p != NULL && j < i)
    {
        j++;
        p = p->next;
    }
    if (p == NULL || j > i)
    {
        log_err("Invalid position");
        return -1;
    }
    *e = p->data;
    return 0;
}

// Locate the element e
int Locate_Elem(LinkList L, ElemType e)
{
    int i = 0;
    LinkList p = L->next;
    while (p != NULL && p->data != e)
    {
        i++;
        p = p->next;
    }
    if (p == NULL)
    {
        log_err("Element not found");
        return -1;
    }
    return i;
}

// Insert an element at position i, 1 <= i <= ListLength(L)
int List_Insert(LinkList L, int i, ElemType e)
{
    int j = 1;
    LinkList p = L;                                 // p points to the head node, which is the 0th node, not the first node.
    while (p != NULL && j < i)
    {
        j++;
        p = p->next;
    }
    if (p == NULL || j > i )
    {
        log_err("Invalid position");
        return -1;
    }
    LinkList s = (LinkList)malloc(sizeof(Node));
    if (s == NULL)
    {
        log_err("Failed to allocate memory for the new node");
        return -1;
    }
    s->data = e;
    s->next = p->next;
    p->next = s;
    return 0;
}

// Delete the element at position i, 1 <= i <= ListLength(L)
int List_Delete(LinkList L, int i, ElemType *e)
{
    int j = 1;
    LinkList p = L;
    while (p != NULL && j < i)
    {
        j++;
        p = p->next;
    }
    if (p == NULL || j > i)
    {
        log_err("Invalid position");
        return -1;
    }
    LinkList q = p->next;
    *e = q->data;
    p->next = q->next;
    free(q);
    return 0;
}

// Traverse the linked list
int List_Traverse(LinkList L, visit node_print)
{
    LinkList p = L->next;
    while (p != NULL)
    {
        node_print(p);
        p = p->next;
    }
    return 0;
}